{
 "cells": [
  {
   "cell_type": "markdown",
   "source": [
    "### 2.5.1. 一个简单的例子"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "8caed062c9b15cba"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "tensor([0., 1., 2., 3.])"
     },
     "execution_count": 1,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "import torch\n",
    "\n",
    "x = torch.arange(4.0)\n",
    "x"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-03-28T07:10:39.433545Z",
     "start_time": "2024-03-28T07:10:37.433535Z"
    }
   },
   "id": "e087db06387e424b",
   "execution_count": 1
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "x.requires_grad_(True)  # 等价于x=torch.arange(4.0,requires_grad=True)\n",
    "x.grad"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-03-28T07:11:00.884851Z",
     "start_time": "2024-03-28T07:11:00.864901Z"
    }
   },
   "id": "7185a66542a03a43",
   "execution_count": 3
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "tensor(28., grad_fn=<MulBackward0>)"
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y = 2 * torch.dot(x, x)\n",
    "y"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-03-28T07:11:30.299942Z",
     "start_time": "2024-03-28T07:11:30.284954Z"
    }
   },
   "id": "2e4de966c5e0debb",
   "execution_count": 5
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "tensor([ 0.,  4.,  8., 12.])"
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "y.backward()\n",
    "x.grad"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-03-28T07:13:58.026849Z",
     "start_time": "2024-03-28T07:13:58.006014Z"
    }
   },
   "id": "3e2d7aa1be0444b9",
   "execution_count": 7
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "tensor([True, True, True, True])"
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.grad == 4 * x"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-03-28T07:14:20.179777Z",
     "start_time": "2024-03-28T07:14:20.170039Z"
    }
   },
   "id": "c6ece1b7c06f0884",
   "execution_count": 8
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "tensor([1., 1., 1., 1.])"
     },
     "execution_count": 12,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 在默认情况下，PyTorch会累积梯度，我们需要清除之前的值\n",
    "x.grad.zero_()\n",
    "x.grad.zero_()\n",
    "y = x.sum()\n",
    "y.backward()\n",
    "x.grad"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-03-28T07:15:22.121407Z",
     "start_time": "2024-03-28T07:15:22.104229Z"
    }
   },
   "id": "486d39fb17bd6d4d",
   "execution_count": 12
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 2.5.2. 非标量变量的反向传播"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "530e776804575398"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "(tensor([0., 1., 4., 9.], grad_fn=<MulBackward0>), tensor([0., 2., 4., 6.]))"
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 对非标量调用backward需要传入一个gradient参数，该参数指定微分函数关于self的梯度。\n",
    "# 本例只想求偏导数的和，所以传递一个1的梯度是合适的\n",
    "x.grad.zero_()\n",
    "y = x * x\n",
    "# 等价于y.backward(torch.ones(len(x)))，torch.ones(len(x))指定每部分的权重都为1，这样就相当于y.sum().backward()\n",
    "# 我们的目的不是计算微分矩阵，而是单独计算批量中每个样本的偏导数之和\n",
    "y.sum().backward()\n",
    "y, x.grad"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-03-28T07:19:02.569244Z",
     "start_time": "2024-03-28T07:19:02.558790Z"
    }
   },
   "id": "39ea27403058f1e5",
   "execution_count": 13
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "(tensor([0., 1., 4., 9.], grad_fn=<MulBackward0>), tensor([0., 2., 4., 6.]))"
     },
     "execution_count": 16,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.grad.zero_()\n",
    "y = x * x\n",
    "y.backward(torch.ones(len(x)))\n",
    "y, x.grad"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-03-28T07:23:10.839701Z",
     "start_time": "2024-03-28T07:23:10.811471Z"
    }
   },
   "id": "6a883225769439b9",
   "execution_count": 16
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 2.5.3. 分离计算"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "b9572a222648428e"
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor([0., 1., 4., 9.])\n"
     ]
    },
    {
     "data": {
      "text/plain": "tensor([True, True, True, True])"
     },
     "execution_count": 26,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.grad.zero_()\n",
    "y = x * x\n",
    "u = y.detach()\n",
    "z = u * x\n",
    "print(u)\n",
    "z.sum().backward()\n",
    "x.grad == u"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-03-28T07:46:05.964977Z",
     "start_time": "2024-03-28T07:46:05.952588Z"
    }
   },
   "id": "56af90648861f12",
   "execution_count": 26
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "tensor([0., 2., 4., 6.])"
     },
     "execution_count": 27,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "x.grad.zero_()\n",
    "y.sum().backward()\n",
    "x.grad"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-03-28T07:46:19.433676Z",
     "start_time": "2024-03-28T07:46:19.416992Z"
    }
   },
   "id": "ea8a4b81af96879a",
   "execution_count": 27
  },
  {
   "cell_type": "markdown",
   "source": [
    "### 2.5.4. Python控制流的梯度计算"
   ],
   "metadata": {
    "collapsed": false
   },
   "id": "7241da938e625298"
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [
    "def f(a):\n",
    "    b = a * 2\n",
    "    while b.norm() < 1000:\n",
    "        b = b * 2\n",
    "    if b.sum() > 0:\n",
    "        c = b\n",
    "    else:\n",
    "        c = 100 * b\n",
    "    return c"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-03-28T07:47:10.132077Z",
     "start_time": "2024-03-28T07:47:10.114348Z"
    }
   },
   "id": "ead327189c648b28",
   "execution_count": 28
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "tensor(0.0694, requires_grad=True)\n",
      "tensor(1136.8286, grad_fn=<MulBackward0>)\n"
     ]
    }
   ],
   "source": [
    "a = torch.randn(size=(), requires_grad=True)\n",
    "print(a)\n",
    "d = f(a)\n",
    "print(d)\n",
    "d.backward()"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-03-28T07:48:03.391953Z",
     "start_time": "2024-03-28T07:48:03.369905Z"
    }
   },
   "id": "c50acc8816f1285d",
   "execution_count": 30
  },
  {
   "cell_type": "code",
   "outputs": [
    {
     "data": {
      "text/plain": "tensor(16384.)"
     },
     "execution_count": 31,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.grad"
   ],
   "metadata": {
    "collapsed": false,
    "ExecuteTime": {
     "end_time": "2024-03-28T07:48:43.444979Z",
     "start_time": "2024-03-28T07:48:43.427471Z"
    }
   },
   "id": "a1f8a2b7766e1483",
   "execution_count": 31
  },
  {
   "cell_type": "code",
   "outputs": [],
   "source": [],
   "metadata": {
    "collapsed": false
   },
   "id": "86190c4b1a914c5a"
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 2
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython2",
   "version": "2.7.6"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
